using System;
using System.Windows;
using System.Windows.Threading;

namespace FluentSilverlight.Commands
{
    public class DelegateCommand<T> : IFsCommand
    {
        private readonly Action<T> executeMethod;
        private readonly Func<bool> canExecuteMethod;

        public event EventHandler CanExecuteChanged;

        public DelegateCommand(Action<T> executeMethod)
        {
            if (executeMethod == null)
                throw new ArgumentNullException("executeMethod", "DelegateCommand Delegate Cannot Be Null");
            this.executeMethod = executeMethod;
        }

        public DelegateCommand(Action<T> executeMethod, Func<bool> canExecuteMethod)
            : this(executeMethod)
        {
            this.canExecuteMethod = canExecuteMethod;
            if (canExecuteMethod == null)
                throw new ArgumentNullException("canExecuteMethod", "DelegateCommand Delegate Cannot Be Null");
        }

        public bool CanExecute()
        {
            if (canExecuteMethod == null) return true;
            return canExecuteMethod();
        }

        public void Execute(T parameter)
        {
            if (executeMethod == null) return;
            executeMethod(parameter);
        }

        bool IFsCommand.CanExecute()
        {
            return CanExecute();
        }

        void IFsCommand.Execute(object parameter)
        {
            Execute((T)parameter);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate")]
        public void RaiseCanExecuteChanged()
        {
            OnCanExecuteChanged();
        }

        protected virtual void OnCanExecuteChanged()
        {
            Dispatcher dispatcher = null;
            if (Deployment.Current != null)
            {
                dispatcher = Deployment.Current.Dispatcher;
            }

            var canExecuteChangedHandler = CanExecuteChanged;
            if (canExecuteChangedHandler == null) return;

            if (dispatcher != null && !dispatcher.CheckAccess())
            {
                dispatcher.BeginInvoke(OnCanExecuteChanged);
            }
            else
            {
                canExecuteChangedHandler(this, EventArgs.Empty);
            }
        }
    }
}